package isquirrel;

import isquirrel.beans.Pair;
import isquirrel.beans.Property;
import isquirrel.beans.User;
import isquirrel.error.UsernameAlreadyUsedException;
import isquirrel.util.HibernateUtil;
import isquirrel.util.Utilities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class UserManager {
	
	public static Serializable registerUser(String firstname, 
									String lastname, 
									String username, 
									String password,
									Date dob,
									String sex,
									Long fbID,
									Integer isInit
								    ) throws UsernameAlreadyUsedException {
		
		User registered_user = getUser(username);
		if (registered_user == null) {
			User u = new User(firstname,
							  lastname,
							  username,
							  Utilities.hashPassword(password),
							  dob,
							  sex,
							  Utilities.createToken(username),
							  fbID,
							  isInit
							  );
			
			return HibernateUtil.getSession().save(u);
			
		} else {
			throw new UsernameAlreadyUsedException();
		}
	}
	
	//get all users from the database
	@SuppressWarnings("unchecked")
	public static List<User> getUsers() {
		return HibernateUtil.getSession().createQuery("from User").list();
	}
	
	//get user by user id
	public static User getUser(Long userID) {
		return (User) HibernateUtil.getSession().load(User.class, userID);
	}
	
	public static User getUser(String username) {
		return (User) HibernateUtil.getSession().createQuery("from User u where u.username = ?")
						.setString(0, username).uniqueResult();
	}
	
	@SuppressWarnings("unchecked")
	public static List<User> getUsersFromFbId(Long fbid) {
		return HibernateUtil.getSession().createQuery("from User u where u.fbID = ?").setLong(0, fbid).list();
	}
	
	public static boolean loginUser(String username, String password) {
		
		User user = getUser(username);
		if (user == null || !user.getPassword().equals(Utilities.hashPassword(password))) {
			return false;
		} else {
			return true;
		}
	}
	
	public static boolean tokenLogin(String username, String token){
		
		User user = getUser(username);
		if (user == null || !user.getToken().equals(token)) {
			//user does not exist or token is wrong
			return false;
		}
		return true;
	
	}
	
	public static void addProperties(List<Property> properties) {
	
	}
	

	
	/**
	 * Returns now many of the tokens match with this user (using firstname, lastname and username)
	 * @param user
	 * @param tokens
	 * @return 
	 */
	public static int countMatches(User user, String[] tokens) {
		int matches = 0;
		for (String token : tokens) {
			if (!token.trim().equals("")) {
				if (user.getFirstName().toUpperCase().contains(token.toUpperCase()) ||
						user.getLastName().toUpperCase().contains(token.toUpperCase()) ||
						user.getUsername().toUpperCase().contains(token.toUpperCase()) ||
						user.getInterests_labels().toString().contains(token.toUpperCase())
						) {
					matches++;
				}
			}
		}
		return matches;
	}
	
	/*
		public static List<User> searchUsers(String query) {
		List<User> allUsers = UserManager.getUsers();
			
		List<User> result = new ArrayList<User>();
		String[] searchTokens = query.split(" ");
		for (User u : allUsers) {	
			if ( countMatches(u,searchTokens) > 0) {
				result.add(u);
			}
		}
	
		return result;
	}

	*/
	public static List<User> searchUsers(String query) {
		List<User> allUsers = UserManager.getUsers();
		
		//occurences of searched user 
		HashMap<User, Pair> results = new HashMap<User, Pair>();
		
		List<User> sortedResults = new ArrayList<User>();
		String[] searchTokens = query.split(" ");
		int i = 0; 
		for (User u : allUsers) {	
			int count; 
			if ( (count = countMatches(u,searchTokens)) > 0) {
				results.put(u, new Pair(count, i));
			}
			i++;
		}
		List<User> mapKeys = new ArrayList<User>(results.keySet());
		List<Pair> mapValues = new ArrayList<Pair>(results.values());
		
		List<Pair> sortedValues = new ArrayList<Pair>();
		sortedValues.addAll(mapValues);
		
		Collections.sort(sortedValues,  Collections.reverseOrder());
		
		for (Pair p : sortedValues) {
			sortedResults.add(mapKeys.get(mapValues.indexOf(p)));		
		}
		return sortedResults;
	}
	
}
